﻿namespace TownCrier.Tests.Services {
    #region Usings

    using System;
    using System.Collections.Generic;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    using Moq;

    using TownCrier.Infrastructure.Contracts;
    using TownCrier.Infrastructure.Entities;
    using TownCrier.Services;
    using TownCrier.Services.Contracts;

    #endregion

    /// <summary>
    ///     Summary description for EventServiceTests
    /// </summary>
    [TestClass]
    // TODO rewrite event service tests to test for new stuff, like persistence
    public class EventServiceTests {
        /// <summary>
        ///     Gets or sets the test context which provides
        ///     information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext { get; set; }

        #region Additional test attributes

        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //

        #endregion

        [TestMethod]
        public void DeliveryService_ShouldImplement_IEventDeliveryService() {
            var service = new EventDeliveryService();

            Assert.IsInstanceOfType(service, typeof(IEventDeliveryService));
        }

        [TestMethod]
        public void DeliveryService_ShouldReturn_ListOfDeliveryResult() {
            var mock = new Mock<IEventDeliveryService>();
            mock.Setup(m => m.DeliverEvent(It.IsAny<Event>()))
                .Returns(
                    new List<DeliveryResult> {
                                                 new DeliveryResult {
                                                                        DeliveryChannel = "Twutter Channel",
                                                                        Message = "return message",
                                                                        Success = true
                                                                    }
                                             });

            var result = mock.Object.DeliverEvent(new Event());

            Assert.IsNotNull(result);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void DeliveryServiceShouldThrowAnErrorIfNoChannelSourcesAreFound() {
            var input = new Event {
                                      Title = "Test event",
                                      Start = DateTime.Now,
                                      End = DateTime.Now.AddDays(2.0),
                                      EventId = Guid.NewGuid(),
                                      Venue = new Venue()
                                  };

            var service = new EventDeliveryService();
            service.DeliverEvent(input);
        }

        [TestMethod]
        public void DeliveryServicePersistenceEventShouldCallRepoAddMethod() {
            var repo = new Mock<IRepository<Cry>>();
            repo.Setup(r => r.Add(It.IsAny<Cry>())).Verifiable();

            var service = new EventDeliveryService(repo.Object);
        }

        [TestMethod]
        public void DeliveryServiceShouldCallDeliverEventForSelectedChannels() {
            var service = new EventDeliveryService();
            var c1 = new Mock<IChannel>();
            var c2 = new Mock<IChannel>();
            c1.Setup(a1 => a1.TransmitMessage(It.IsAny<Event>())).Returns((Event e) => new DeliveryResult());
            c2.Setup(a2 => a2.TransmitMessage(It.IsAny<Event>())).Returns((Event e) => new DeliveryResult());

            var input = new Event {
                                      SelectedChannels = new List<IChannel> { c1.Object, c2.Object },
                                      Venue = new Venue()
                                  };

            var result = service.DeliverEvent(input);

            c1.Verify(c1a => c1a.TransmitMessage(It.IsAny<Event>()));
            c2.Verify(c2a => c2a.TransmitMessage(It.IsAny<Event>()));
        }

        [TestMethod]
        public void DeliveryServiceShouldCallPersistenceMethod() {
            //Assert.Fail("Needs to be implemented");
            var realservice = new EventDeliveryService();
            var service = new Mock<IEventDeliveryService>();
            var c1 = new Mock<IChannel>();
            var c2 = new Mock<IChannel>();

            var input = new Event {
                                      SelectedChannels = new List<IChannel> { c1.Object, c2.Object },
                                      Venue = new Venue()
                                  };

            var result = service.Object.DeliverEvent(new Event());

            service.Verify(s => s.PersistEvent(It.IsAny<Event>(), It.IsAny<IEnumerable<DeliveryResult>>()));
        }
    }
}
